package exec;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client {

    private int numPort;
    private String ipAddress;
    private Socket socket = null;
    private String nickname;
    private HashMap<String, FileOutputEx> mapFileOutPut;
    GUI gui;
    Comm comm = null;

    public Client(String server, String port, String nickname, GUI gui) {
        try {
            ipAddress = server;
            numPort = Integer.parseInt(port);
            this.nickname = nickname;
            this.gui = gui;
            mapFileOutPut = new HashMap<String, FileOutputEx>();
            System.out.println("\nConnexion...");
            gui.updateStatus("Connexion...");
            socket = new Socket(ipAddress, numPort);

            comm = new Comm(socket, this);
            comm.start();

        } catch (UnknownHostException e) {
            System.out.println("Le serveur spécifié est inconnu. Vérifiez les paramètres.");
        } catch (ConnectException e) {
            System.out.println("Le serveur spécifié n'est pas lancé. Vérifiez les paramètres sur l'hôte distant.");
        } catch (IllegalArgumentException e) {
            System.out.println("Numero de port trop grand.");
        } catch (Exception e) {
            System.out.println(e.toString());
        }

    }

    public void connect() {
        try {
            Message m = new Message(Message.CONNECT, nickname, ipAddress, "Je me connecte");
            comm.send(m);
            gui.dumpTextArea();
            Thread.sleep(500);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void disconnect() {
        Message m = new Message(Message.DISCONNECT, nickname, ipAddress, "");
        comm.send(m);
    }

    public void parseMessage(Comm comm) {
        switch (comm.message.getType()) {
            case Message.CONNECT:
                gui.showConnectMenu(false);
                gui.showAll(true);
                gui.updateStatus("Connecté.");
                gui.setTitle("Welcome to our chat, " + getNickname() + "!");
                break;
            case Message.DISCONNECT:
                System.err.println("Case disconnect");
                try {
                    comm.close();
                    gui.showConnectMenu(true);
                    gui.alert(new String(comm.message.getData()));
                    gui.showAll(false);
                } catch (Exception ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("Now disconnected.");
                break;
            case Message.MESSAGE:
                boolean all = (comm.message.getNickDest().equals("All") || comm.message.getNickSrc().equals("Server"));
                if (!all) {
                    gui.updateStatus("Nouveau message de : " + comm.message.getNickSrc() + ".");
                    // gui.flashLightTab(comm.message.getNickSrc());
                }
                gui.updateTextArea(comm.message.getNickSrc(), new String(comm.message.getData()), all);
                break;
            case Message.LIST:
                System.err.println("Case List");
                System.out.println("New list is : " + new String(comm.message.getData()));
                gui.updateClientList(new String(comm.message.getData()));
                break;
            case Message.WRITING:
                gui.updateStatus(comm.message.getNickSrc() + " est en train d'écrire...");
                break;
            case Message.NOT_WRITING:
                gui.updateStatus("Connecté.");
                break;
            case Message.FILENAME:
                gui.updateStatus("Récéption d'un fichier de la part de : " + comm.message.getNickSrc());
                try {
                    /*
                     * On peut pas savoir si on va pas avoir une autre réception
                     * de fichier dans les secondes qui suivent. Pour ne pas
                     * avoir a changer des choses dans Comm (on continue avec
                     * parseMessage()), je crée un FileOutputStream ici que
                     * j'associe à l'emmeteur du fichier. TODO : Ça plantera si
                     * le même emmeteur envoie deux fichiers à la fois. A gérer.
                     */
                    FileOutputEx fOutput = new FileOutputEx(new String(comm.message.getData()));
                    mapFileOutPut.put(comm.message.getNickSrc(), fOutput);
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                }
                break;
            case Message.FILESIZE:
                gui.updateStatus("Taille du fichier : " + new String(comm.message.getData()) + " octets.");
                /*
                 * Bon en fait la, FILESIZE je vois pas du tout à quoi ça me
                 * sert, j'en ai pas besoin. Je retire. Obligatoire si on reste
                 * dans ce délire la. En fait on se complique la vie à mort.
                 * Enjoy la création d'une classe en plus. Soit ya quelque chose
                 * qui m'échappe, soit on nous fait faire n'importe quoi. Enjoy
                 * aussi la conversion byte[] => int. Youpidou.
                 */
                System.out.println("Taille fichier : " + new String(comm.message.getData()));
                mapFileOutPut.get(comm.message.getNickSrc()).setFileSize(Integer.parseInt(new String(comm.message.getData())));
                gui.getProgresBar().setVisible(true);
                
                gui.getProgresBar().setValue(0);
                gui.getProgresBar().setIndeterminate(false);
                gui.getProgresBar().setBorderPainted(true);
                gui.getProgresBar().setEnabled(true);
                gui.getProgresBar().setOpaque(true);
                gui.getProgresBar().setStringPainted(true);
                gui.getProgresBar().setMaximum(Integer.valueOf(new String(comm.message.getData())));
                // Ayé, on a notre fOutput ouvert avec son fileSize. Enfin.
                break;
            case Message.FILE_CHUNK:
                gui.updateStatus("Réception en cours ... ");
                FileOutputEx fOutput = mapFileOutPut.get(comm.message.getNickSrc());
                // Cas où il reste un seul message à recevoir pour completer le fichier
                if (fOutput.getFileSize() < 1024 && fOutput.getFileSize() > 0) {
                    try {
                        fOutput.write(comm.message.getData(), 0, fOutput.getFileSize());
                        gui.getProgresBar().setValue(gui.getProgresBar().getMaximum());
                        fOutput.close();
                        mapFileOutPut.remove(comm.message.getNickSrc());
                        System.out.println("Cas fin");
                        gui.updateStatus("Fichier reçu.");
                    } catch (IOException ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    // Fichier vide
                } else if (fOutput.getFileSize() == 0) {
                    try {
                        fOutput.close();
                        System.out.println("Cas fileSize == 0");
                        mapFileOutPut.remove(comm.message.getNickSrc());
                    } catch (IOException ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    // Fichier > 1024o    
                    try {
                        fOutput.write(comm.message.getData());
                        gui.getProgresBar().setValue(gui.getProgresBar().getValue() + 1024);
                        fOutput.setFileSize(fOutput.getFileSize() - 1024);
                        System.err.println("fOutPut filsize : " + fOutput.getFileSize());
                    } catch (IOException ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                break;
        }

    }

    void sendMessage(String currentTab, String str) {
        str = parseSmileys(str);
        Message ms = new Message(Message.MESSAGE, nickname, currentTab, str);
        comm.send(ms);
        gui.updateTextArea(nickname, str, currentTab.equals("All"));
    }

    public void heyImWriting(String currentTab) {
        Message ms = new Message(Message.WRITING, nickname, currentTab, "");
        comm.send(ms);
    }

    public void heyImNotWritingAnymore(String currentTab) {
        Message ms = new Message(Message.NOT_WRITING, nickname, currentTab, "");
        comm.send(ms);
    }

    public void sendFile(String currentTab, File file) throws FileNotFoundException, IOException, InterruptedException {
        if (currentTab.equals("All")) {
            gui.alert("Vous ne pouvez envoyer un fichier qu'a un destinataire à la fois.");
        } else {
            // Envoi du nom de fichier
            Message ms = new Message(Message.FILENAME, nickname, currentTab, file.getName());
            comm.send(ms);
            // Envoi de la taille du fichier (utilisé pour la reconstruction)
            ms = new Message(Message.FILESIZE, nickname, currentTab, String.valueOf(file.length()));
            comm.send(ms);
            // Envoi du fichier en flot d'octets, dans un tampon parceque les tampons c'est mieux que les serviettes
            // Enfin ça c'est mon idée de départ, mais j'suis pas sur de m'en sortir alors du coup j'utilise une serviette
            // BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            FileInputStream fInput = null;
            try {
                byte[] buffer = new byte[1024];
                int length;
                fInput = new FileInputStream(file);
                // fInput.read(buffer) == -1 <==> Rien n'a été écrit dans buffer
                
                gui.getProgresBar().setVisible(true);
                
                gui.getProgresBar().setValue(0);
                gui.getProgresBar().setIndeterminate(false);
                gui.getProgresBar().setBorderPainted(true);
                gui.getProgresBar().setEnabled(true);
                gui.getProgresBar().setOpaque(true);
                gui.getProgresBar().setStringPainted(true);
                gui.getProgresBar().setMaximum(Integer.valueOf(String.valueOf(file.length())));
                
                while ((length = fInput.read(buffer)) != -1) {

                    // Les vla', nos File_Chunk. Tant qu'il reste des bits dans le fInput on balance des paquets de 1024 octets.
                    ms = new Message(Message.FILE_CHUNK, nickname, currentTab, buffer);
                    comm.send(ms); 
                    gui.getProgresBar().setValue(gui.getProgresBar().getValue() +  length);
                    
                    Thread.sleep(40);
                   
                    
                    System.out.println("Taille = " + length);
                }
            } finally {
                if (fInput != null) {
                    fInput.close();
                    System.err.println("Fichier envoyé, coco.");
                }
            }
        }
    }

    public String getNickname() {
        return this.nickname;
    }

    public boolean isConnected() {
        if (socket != null) {
            return !socket.isClosed();
        } else {
            return false;
        }

    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
     private String parseSmileys(String str) {
        if (str.contains(":)")) {
            str = str.replace(":)", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/1.gif\" />");
        }
        if (str.contains("(^^)")) {
            str = str.replace("(^^)", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/2.gif\" />");
        }
        if (str.contains(":D")) {
            str = str.replace(":D", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/3.gif\" />");
        }
        if (str.contains("-_-")) {
            str = str.replace("-_-", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/4.gif\" />");
        }
        if (str.contains(":p")) {
            str = str.replace(":p", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/p.gif\" />");
        }
        if (str.contains("oO")) {
            str = str.replace("oO", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/oO.gif\" />");
        }
        if (str.contains("(xp)")) {
            str = str.replace("(xp)", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/xp.gif\" />");
        }
        if (str.contains("(gangnam)")) {
            str = str.replace("(gangnam)", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/gangnam.gif\" />");
        }
        if (str.contains("(lama)")) {
            str = str.replace("(lama)", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/lama.gif\" />");
        }
        if (str.contains("banane")) {
            str = str.replace("banane", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/banane.gif\" />");
        }
        if (str.contains("adrian")) {
            str = str.replace("adrian", "<img src=\"http://fdr.family.free.fr/iut/minichat/smileys/adrian.jpg\" />");
        }
        if (str.contains("Carly Rae Jepsen")) {
            str = str.replace("Carly Rae Jepsen", "<b>Did you just say Carly Rae Jepsen ?? Hmm...</b><i><br /><br />Hey, I just met you,<br />And this is crazy,<br />But here's my number,<br />"
                    + "So call me, maybe?<br /><br />It's hard to look right,<br />At you baby,<br />But here's my number,<br />So call me, maybe?</i><br />");
        }
        if (str.contains("PSY")) {
            str = str.replace("PSY", "<b>Did you just say PSY ?? Ohhh !</b><i><br /><br />Oppan Gangnam style, Gangnam style<br />Oppan Gangnam style, Gangnam style<br />"
                    + "Oppan Gangnam style<br /><br />Eh- Sexy Lady, Oppan Gangnam style<br />Eh- Sexy Lady oh oh oh oh</i><br />");
        }
         return str;
    }
}
